package gis

import (
	"dgo/goutils/utils"
	"math/rand"
	"strings"
)

type Polygon struct {
	leftTopX, leftTopY         float64
	rightBottomX, rightBottomY float64
	xlist                      []float64
	ylist                      []float64
}

func NewPolygon() *Polygon {
	rval := &Polygon{
		xlist: make([]float64, 0),
		ylist: make([]float64, 0),
	}
	return rval
}

/*
*

	先调用SearchBoundRect
*/
func (this *Polygon) LeftTop() (x, y float64) {
	return this.leftTopX, this.leftTopY
}

/*
*

	先调用SearchBoundRect
*/
func (this *Polygon) RightBottom() (x, y float64) {
	return this.rightBottomX, this.rightBottomY
}

/*
*

	先调用SearchBoundRect
*/
func (this *Polygon) Range(xstart, ystart, xdis, ydis float64, cb func(x, y float64) bool) {
	x0, y0 := this.LeftTop()
	x := xstart
	y := ystart
	if x == 0 {
		x = x0
	}

	if y == 0 {
		y = y0
	}

	for y > this.rightBottomY {
		for x < this.rightBottomX {
			if this.Contain(x, y) {
				if !cb(x, y) {
					return
				}
			}
			x += xdis
		}
		y -= ydis
		x = x0
	}
}

func (this *Polygon) SearchBoundRect() {
	if len(this.xlist) == 0 {
		return
	}

	ltopX := this.xlist[0]
	ltopY := this.ylist[0]
	rbottomX := this.xlist[0]
	rbottomY := this.ylist[0]

	for i := 1; i < len(this.xlist); i++ {

		if this.xlist[i] > rbottomX {
			rbottomX = this.xlist[i]
		}
		if this.xlist[i] < ltopX {
			ltopX = this.xlist[i]
		}

		if this.ylist[i] > ltopY {
			ltopY = this.ylist[i]
		}
		if this.ylist[i] < rbottomY {
			rbottomY = this.ylist[i]
		}
	}

	this.leftTopX = ltopX
	this.leftTopY = ltopY
	this.rightBottomX = rbottomX
	this.rightBottomY = rbottomY
}

func (this *Polygon) Rand() (x, y float64) {
	if this.leftTopY == 0 && this.leftTopX == 0 && this.rightBottomX == 0 && this.rightBottomY == 0 {
		return
	}

	for i := 0; i < 1000; i++ {
		lvRnd := float64(rand.Intn(9999)) / 10000
		x = this.leftTopX + ((this.rightBottomX - this.leftTopX) * lvRnd)

		lvRnd = float64(rand.Intn(9999)) / 10000
		y = this.leftTopY + ((this.rightBottomY - this.leftTopY) * lvRnd)

		if this.Contain(x, y) {
			return
		}
	}

	x = 0
	y = 0
	return
}

/*
*

	X1 Y1,X2 Y2,X3 Y3
*/
func (this *Polygon) ParseSimpleWKT_XY(str string) bool {

	strs := strings.Split(str, ",")
	if len(strs) < 3 {
		return false
	}
	this.xlist = make([]float64, 0, len(strs))
	this.ylist = make([]float64, 0, len(strs))
	for _, v := range strs {
		s := utils.Trim(v)
		if len(s) > 0 {
			p := strings.SplitN(s, " ", 2)
			this.xlist = append(this.xlist, utils.StrToFloat64Def(utils.Trim(p[0]), 0))
			this.ylist = append(this.ylist, utils.StrToFloat64Def(utils.Trim(p[1]), 0))
		}
	}

	return len(this.xlist) >= 3
}

func (this *Polygon) IsValid() bool {
	return len(this.xlist) >= 3 && len(this.xlist) == len(this.ylist)
}

/*
*

	是否包含, 射线发
*/
func (this *Polygon) Contain(x, y float64) bool {
	n := len(this.xlist)
	if n != len(this.ylist) {
		return false
	}

	if n < 3 {
		return false
	}

	r := false
	i := 0
	j := n - 1
	for {
		if i >= n {
			break
		}

		b := (this.ylist[i] > y) != (this.ylist[j] > y)
		b = b && (x < (this.xlist[j]-this.xlist[i])*(y-this.ylist[i])/
			(this.ylist[j]-this.ylist[i])+this.xlist[i])
		if b {
			r = !r
		}
		j = i
		i++
	}

	return r
}
